{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "dc90de44-ddd1-4bd6-afd0-9852778ddf36",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 正则表达式\n",
    "import re\n",
    "\n",
    "# 科学计算\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "\n",
    "# 绘图\n",
    "import matplotlib.pyplot as plt\n",
    "import seaborn as sns\n",
    "\n",
    "# NLP\n",
    "from nltk import word_tokenize\n",
    "\n",
    "# 机器学习\n",
    "from sklearn.model_selection import train_test_split\n",
    "from tensorflow import keras\n",
    "\n",
    "from keras.preprocessing.text import Tokenizer\n",
    "from keras.preprocessing.sequence import pad_sequences\n",
    "from keras.models import Sequential\n",
    "from keras.layers import Dense, Embedding, GRU, SpatialDropout1D\n",
    "# from keras.utils.np_utils import to_categorical\n",
    "from keras.callbacks import EarlyStopping\n",
    "from keras.layers import Dropout"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "ccb2ed50-a8b4-41c4-94f9-aec3c997463e",
   "metadata": {},
   "outputs": [],
   "source": [
    "#STOPWORDS = set(stopwords.words('english'))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "05f194c9-1499-413d-a210-1ca5378159b5",
   "metadata": {},
   "source": [
    "#### 数据文件读取"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "da294dcc-2470-4ab7-927a-01cfa7f0141f",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 定义一个空函数，用于忽略错误的行  \n",
    "def ignore_bad_lines(line):  \n",
    "    pass "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "96ba9998-e53c-4032-a410-29488e2fcdff",
   "metadata": {},
   "outputs": [],
   "source": [
    "df=pd.read_csv('../../data/mugulian/mugulian-text.csv')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a6740cb2-ee44-410e-a3ac-b3d45e06dd14",
   "metadata": {},
   "source": [
    "#### 数据格式化"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "e792aef6-9a3c-44c8-8009-133be15d2c32",
   "metadata": {},
   "outputs": [
    {
     "ename": "KeyError",
     "evalue": "'review'",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mKeyError\u001b[0m                                  Traceback (most recent call last)",
      "File \u001b[0;32m/opt/anaconda3/envs/science39/lib/python3.9/site-packages/pandas/core/indexes/base.py:3791\u001b[0m, in \u001b[0;36mIndex.get_loc\u001b[0;34m(self, key)\u001b[0m\n\u001b[1;32m   3790\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m-> 3791\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_engine\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget_loc\u001b[49m\u001b[43m(\u001b[49m\u001b[43mcasted_key\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m   3792\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mKeyError\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m err:\n",
      "File \u001b[0;32mindex.pyx:152\u001b[0m, in \u001b[0;36mpandas._libs.index.IndexEngine.get_loc\u001b[0;34m()\u001b[0m\n",
      "File \u001b[0;32mindex.pyx:181\u001b[0m, in \u001b[0;36mpandas._libs.index.IndexEngine.get_loc\u001b[0;34m()\u001b[0m\n",
      "File \u001b[0;32mpandas/_libs/hashtable_class_helper.pxi:7080\u001b[0m, in \u001b[0;36mpandas._libs.hashtable.PyObjectHashTable.get_item\u001b[0;34m()\u001b[0m\n",
      "File \u001b[0;32mpandas/_libs/hashtable_class_helper.pxi:7088\u001b[0m, in \u001b[0;36mpandas._libs.hashtable.PyObjectHashTable.get_item\u001b[0;34m()\u001b[0m\n",
      "\u001b[0;31mKeyError\u001b[0m: 'review'",
      "\nThe above exception was the direct cause of the following exception:\n",
      "\u001b[0;31mKeyError\u001b[0m                                  Traceback (most recent call last)",
      "Cell \u001b[0;32mIn[18], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m X\u001b[38;5;241m=\u001b[39m\u001b[43mdf\u001b[49m\u001b[43m[\u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mreview\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m]\u001b[49m\n\u001b[1;32m      2\u001b[0m Y \u001b[38;5;241m=\u001b[39m pd\u001b[38;5;241m.\u001b[39mget_dummies(df[\u001b[38;5;124m'\u001b[39m\u001b[38;5;124msentiment\u001b[39m\u001b[38;5;124m'\u001b[39m],columns\u001b[38;5;241m=\u001b[39mdf[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124msentiment\u001b[39m\u001b[38;5;124m\"\u001b[39m])\u001b[38;5;241m.\u001b[39mvalues\n\u001b[1;32m      3\u001b[0m Y\n",
      "File \u001b[0;32m/opt/anaconda3/envs/science39/lib/python3.9/site-packages/pandas/core/frame.py:3893\u001b[0m, in \u001b[0;36mDataFrame.__getitem__\u001b[0;34m(self, key)\u001b[0m\n\u001b[1;32m   3891\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mcolumns\u001b[38;5;241m.\u001b[39mnlevels \u001b[38;5;241m>\u001b[39m \u001b[38;5;241m1\u001b[39m:\n\u001b[1;32m   3892\u001b[0m     \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_getitem_multilevel(key)\n\u001b[0;32m-> 3893\u001b[0m indexer \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcolumns\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget_loc\u001b[49m\u001b[43m(\u001b[49m\u001b[43mkey\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m   3894\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m is_integer(indexer):\n\u001b[1;32m   3895\u001b[0m     indexer \u001b[38;5;241m=\u001b[39m [indexer]\n",
      "File \u001b[0;32m/opt/anaconda3/envs/science39/lib/python3.9/site-packages/pandas/core/indexes/base.py:3798\u001b[0m, in \u001b[0;36mIndex.get_loc\u001b[0;34m(self, key)\u001b[0m\n\u001b[1;32m   3793\u001b[0m     \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(casted_key, \u001b[38;5;28mslice\u001b[39m) \u001b[38;5;129;01mor\u001b[39;00m (\n\u001b[1;32m   3794\u001b[0m         \u001b[38;5;28misinstance\u001b[39m(casted_key, abc\u001b[38;5;241m.\u001b[39mIterable)\n\u001b[1;32m   3795\u001b[0m         \u001b[38;5;129;01mand\u001b[39;00m \u001b[38;5;28many\u001b[39m(\u001b[38;5;28misinstance\u001b[39m(x, \u001b[38;5;28mslice\u001b[39m) \u001b[38;5;28;01mfor\u001b[39;00m x \u001b[38;5;129;01min\u001b[39;00m casted_key)\n\u001b[1;32m   3796\u001b[0m     ):\n\u001b[1;32m   3797\u001b[0m         \u001b[38;5;28;01mraise\u001b[39;00m InvalidIndexError(key)\n\u001b[0;32m-> 3798\u001b[0m     \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mKeyError\u001b[39;00m(key) \u001b[38;5;28;01mfrom\u001b[39;00m \u001b[38;5;21;01merr\u001b[39;00m\n\u001b[1;32m   3799\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mTypeError\u001b[39;00m:\n\u001b[1;32m   3800\u001b[0m     \u001b[38;5;66;03m# If we have a listlike key, _check_indexing_error will raise\u001b[39;00m\n\u001b[1;32m   3801\u001b[0m     \u001b[38;5;66;03m#  InvalidIndexError. Otherwise we fall through and re-raise\u001b[39;00m\n\u001b[1;32m   3802\u001b[0m     \u001b[38;5;66;03m#  the TypeError.\u001b[39;00m\n\u001b[1;32m   3803\u001b[0m     \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_check_indexing_error(key)\n",
      "\u001b[0;31mKeyError\u001b[0m: 'review'"
     ]
    }
   ],
   "source": [
    "X=df['review']\n",
    "Y = pd.get_dummies(df['sentiment'],columns=df[\"sentiment\"]).values\n",
    "Y\n",
    "df.describe()\n",
    "sns.countplot(df['sentiment'])\n",
    "g=[]\n",
    "for i in df['review']:\n",
    "    g.append(i)\n",
    "len(g)\n",
    "maxl = max([len(s) for s in g])\n",
    "print ('Maximum sequence length in the list of sentences:', maxl)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dd88e5c7-e888-49e5-bdcd-d5bc2c86752d",
   "metadata": {},
   "source": [
    "#### 数据预处理"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3eb7ef2c-d517-4f82-b9d5-82d6c7d100cf",
   "metadata": {},
   "outputs": [],
   "source": [
    "tokenizer = Tokenizer(num_words=50000, filters='!\"#$%&()*+,-./:;<=>?@[\\]^_`{|}~', lower=True)\n",
    "tokenizer.fit_on_texts(df['review'].values)\n",
    "word_index = tokenizer.word_index\n",
    "print('Found %s unique tokens.' % len(word_index))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5433fbd4-88a7-43e9-95b0-e87ff7dfbe57",
   "metadata": {},
   "source": [
    "#### 构造数据集"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a3fd852a-3d62-43d5-806c-6a9805ff590b",
   "metadata": {},
   "outputs": [],
   "source": [
    "X = tokenizer.texts_to_sequences(df['review'].values)\n",
    "X = pad_sequences(X, maxlen=3000)\n",
    "Y = pd.get_dummies(df['sentiment'],columns=df[\"sentiment\"]).values\n",
    "Y\n",
    "df.tail(7)\n",
    "X_train, X_test, Y_train, Y_test = train_test_split(X,Y, test_size = 0.3, random_state = 42)\n",
    "print(X_train.shape,Y_train.shape)\n",
    "print(X_test.shape,Y_test.shape)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f18ac804-2f20-4b9e-be36-c963a6a97d4a",
   "metadata": {},
   "source": [
    "#### 模型训练"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a80b211f",
   "metadata": {},
   "source": [
    "GRU 输入的是一维序列数据 $x_t$ \n",
    "\n",
    "GRU 中的线性变换（如  $W_z \\cdot [h_{t-1}, x_t]$ ）使用全连接层。\n",
    "\n",
    "GRU：处理语言模型、时间序列预测等一维任务。\n",
    "\n",
    "ConvGRU 的门控公式类似 GRU，但权重变为卷积核：\n",
    "\n",
    "$z_t = \\sigma(W_z * [h_{t-1}, x_t])$\n",
    "\n",
    "$r_t = \\sigma(W_r * [h_{t-1}, x_t])$\n",
    "\n",
    "$\\tilde{h}_t = \\text{tanh}(W_h * [r_t \\odot h_{t-1}, x_t])$\n",
    "\n",
    "$h_t = (1 - z_t) \\odot h_{t-1} + z_t \\odot \\tilde{h}_t$\n",
    "\n",
    "其中，\\(*\\) 是卷积操作，$\\odot$ 是逐元素乘法。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "cb08c8ac-18f1-4d9a-a5a3-610d157a7bac",
   "metadata": {},
   "outputs": [],
   "source": [
    "\n",
    "# model=Sequential()\n",
    "# model.add(Embedding(50000,100,input_length=3000))\n",
    "# model.add(SpatialDropout1D(0.2))\n",
    "# model.add(LSTM(100, dropout=0.2, recurrent_dropout=0.2))\n",
    "# model.add(Dense(7, activation='softmax'))\n",
    "# model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])\n",
    "# model.summary()\n",
    "#from    tensorflow import keras\n",
    "#from    tensorflow.keras import layers, optimizers, datasets\n",
    "#from tensorflow.keras.models import Sequential\n",
    "#from tensorflow.keras.layers import*\n",
    "#from keras import Sequential\n",
    "#from keras.layers import *\n",
    "model=Sequential()\n",
    "model.add(Embedding(50000,100,input_length=3000))\n",
    "model.add(GRU(100))\n",
    "model.add(Dense(50, activation='relu'))\n",
    "#model.add(SpatialDropout1D(0.2))\n",
    "#model.add(GRU(100, dropout=0.2, recurrent_dropout=0.4))\n",
    "model.add(Dense(7, activation='softmax'))\n",
    "model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])\n",
    "model.summary()\n",
    "#callbacks_list=keras.callbacks.EarlyStopping(monitor='val_loss', patience=0, verbose=0, mode='auto')\n",
    "callbacks_list = [EarlyStopping(monitor='val_loss', patience=3)]\n",
    "history = model.fit(X_train,  Y_train,\n",
    "                    epochs=1,\n",
    "                    batch_size=32,\n",
    "                    validation_split=0.3,\n",
    "                    shuffle=True,\n",
    "                    callbacks=callbacks_list)\n",
    "accr = model.evaluate(X_test,Y_test)\n",
    "print('Test set\\n  Loss: {:0.3f}\\n  Accuracy: {:0.3f}'.format(accr[0],accr[1]))"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.18"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
